import java.io.IOException;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.SocketException;
import java.util.UUID;

/**
 * UDP 提供者，用于提供服务
 */
public class UDPProvider {
    public static void main(String[] args) throws IOException {
        // 生成唯一标识
        String sn = UUID.randomUUID().toString();
        Provider provider = new Provider(sn);
        provider.start();

        // 读取任意字符，都可以退出
        System.in.read();
        provider.exit();
    }

    /**
     * 要求
     * 1、程序能一直监听是否有UDP Searcher
     * 2、程序能随时停止监听UDP Searcher
     *
     * 则需要新建一个线程和while循环，管理这些Searcher
     */
    private static class Provider extends Thread {
        private final String sn; // 标识自己
        private boolean done = false; // 标识程序的状态，随时可以停止
        private DatagramSocket ds = null;

        public Provider(String sn) {
            super();
            this.sn = sn;
        }

        @Override
        public void run() {
            super.run();

            System.out.println("UDPProvider Started.");

            try {
                // 监听
                ds = new DatagramSocket(20000);

                while (!done) {

                    // 作为接收者，指定一个端口用于数据接收

                    // 构建接收实体
                    final byte[] buf = new byte[512];
                    DatagramPacket receivePack = new DatagramPacket(buf, buf.length);

                    /**
                     * 接收
                     */
                    ds.receive(receivePack); // 阻塞操作

                    // 打印接收到的信息与发送者的信息
                    // 发送者的IP地址
                    String ip = receivePack.getAddress().getHostAddress();
                    // 发送者的端口
                    int port = receivePack.getPort();
                    // 数据大小
                    int dataLen = receivePack.getLength();

                    String data = new String(receivePack.getData(), 0, dataLen); // 假设报文内容都是String
                    System.out.println("UDPProvider receive from ip:" + ip + "\tport:" + port + "\tdata:" + data);

                    /**
                     * 拿到UDP Searcher端口
                     */
                    int responsePort = MessageCreator.parsePort(data); // 解析端口号，接下来判断端口号是否有效
                    if (responsePort != -1) {
                        /**
                         * 如果端口号有效，则构建一份回送数据
                         */
                        String responseData = MessageCreator.buildWithSn(sn);
                        byte[] responseDataBytes = responseData.getBytes(); // 未设定字符集

                        // 直接根据发送者构建一个回送报文
                        DatagramPacket responsePack = new DatagramPacket(responseDataBytes,
                                responseDataBytes.length, receivePack.getAddress(), responsePort); // 指定的端口号

                        ds.send(responsePack);
                    }
                }

            } catch (Exception e) {
                e.printStackTrace();
            } finally {
                close(); // 释放所有资源
            }

            /**
             * 完成
             */
            System.out.println("UDPProvider Finished");

        }

        private void close() {
            if (ds != null) {
                System.out.println("关闭所有资源");
                ds.close(); // 结束socket
                ds = null; // 置为空
            }
        }

        /**
         * 随时能停止
         */
        void exit() {
            this.done = true;
            close();
        }
    }
}
